# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

"""元组类型测试

测试 tuple 类型的各种功能，包括：
- 强类型元组（tuple[int, str, ...]）
- 弱类型元组（tuple）
- 元组字面量构造
- 元组索引访问
- 元组与 Any 类型转换
- 异步函数中的元组
"""

from typing import Any

from gtest import EXPECT_EQ, EXPECT_TRUE, EXPECT_FALSE, test

from mc.future import ensure_future


# ============================================================================
# 基础元组字面量测试
# ============================================================================


def my_tuple_test(tp: tuple) -> int:
    total = 0
    for i in tp:
        total += i
    return total


@test("TupleBasic", "LiteralConstruction")
def test_tuple_literal_construction():
    """测试基础元组字面量构造"""

    # 强类型元组
    t1: tuple[int, int, int] = (1, 2, 3)
    EXPECT_EQ(len(t1), 3)
    EXPECT_EQ(t1[0], 1)
    EXPECT_EQ(t1[1], 2)
    EXPECT_EQ(t1[2], 3)

    # 弱类型元组（注意：弱类型元组在 C++ 中映射为 mc::variants）
    t2: tuple = (1, "hello", 3.14)
    EXPECT_EQ(len(t2), 3)
    # 弱类型元组的索引访问返回 variant，需要转换
    EXPECT_EQ(t2[0], 1)
    EXPECT_EQ(t2[1], "hello")
    EXPECT_EQ(t2[2], 3.14)


@test("TupleBasic", "EmptyTuple")
def test_empty_tuple():
    """测试空元组"""

    t1: tuple[()] = ()
    EXPECT_EQ(len(t1), 0)

    t2: tuple = ()
    EXPECT_EQ(len(t2), 0)


@test("TupleBasic", "SingleElementTuple")
def test_single_element_tuple():
    """测试单元素元组"""

    t1: tuple[int] = (42,)
    EXPECT_EQ(len(t1), 1)
    EXPECT_EQ(t1[0], 42)

    t2: tuple = ("hello",)
    EXPECT_EQ(len(t2), 1)
    EXPECT_EQ(t2[0], "hello")


@test("TupleBasic", "MixedTypeTuple")
def test_mixed_type_tuple():
    """测试混合类型元组"""

    t: tuple[int, str, bool, float] = (1, "hello", True, 3.14)
    EXPECT_EQ(len(t), 4)
    EXPECT_EQ(t[0], 1)
    EXPECT_EQ(t[1], "hello")
    EXPECT_EQ(t[2], True)
    EXPECT_EQ(t[3], 3.14)


# ============================================================================
# 元组索引访问测试
# ============================================================================


@test("TupleAccess", "IndexAccess")
def test_tuple_index_access():
    """测试元组索引访问"""

    t: tuple[int, str, int] = (1, "hello", 3)
    EXPECT_EQ(t[0], 1)
    EXPECT_EQ(t[1], "hello")
    EXPECT_EQ(t[2], 3)


@test("TupleAccess", "NegativeIndex")
def test_tuple_negative_index():
    """测试负索引访问"""

    t: tuple[int, str, int] = (1, "hello", 3)
    EXPECT_EQ(t[-1], 3)
    EXPECT_EQ(t[-2], "hello")
    EXPECT_EQ(t[-3], 1)


@test("TupleAccess", "IndexOutOfRange")
def test_tuple_index_out_of_range():
    """测试索引越界（应该抛出异常）"""

    t: tuple[int, int] = (1, 2)
    try:
        _ = t[len(t) + 1]  # 应该抛出异常
        EXPECT_TRUE(False)  # 不应该到达这里
    except Exception:
        EXPECT_TRUE(True)  # 应该抛出异常


# # ============================================================================
# # 元组与 Any 类型转换测试
# # ============================================================================


@test("TupleConversion", "StrongToAny")
def test_strong_tuple_to_any():
    """测试强类型元组赋值给 Any 类型"""

    t: tuple[int, str, int] = (1, "hello", 3)
    x: Any = t  # 赋值给 Any

    # 应该可以访问
    EXPECT_EQ(len(x), 3)
    EXPECT_EQ(x[0], 1)
    EXPECT_EQ(x[1], "hello")
    EXPECT_EQ(x[2], 3)


@test("TupleConversion", "AnyToStrong")
def test_any_to_strong_tuple():
    """测试从 Any 类型恢复强类型元组"""

    x: Any = (1, "hello", 3)
    t: tuple[int, str, int] = x  # 从 Any 恢复

    EXPECT_EQ(len(t), 3)
    EXPECT_EQ(t[0], 1)
    EXPECT_EQ(t[1], "hello")
    EXPECT_EQ(t[2], 3)


@test("TupleConversion", "WeakToAny")
def test_weak_tuple_to_any():
    """测试弱类型元组赋值给 Any"""

    t: tuple = (1, "hello", 3.14)
    x: Any = t

    EXPECT_EQ(len(x), 3)
    EXPECT_EQ(x[0], 1)
    EXPECT_EQ(x[1], "hello")
    EXPECT_EQ(x[2], 3.14)


@test("TupleConversion", "AnyToWeak")
def test_any_to_weak_tuple():
    """测试从 Any 恢复弱类型元组"""

    x: Any = (1, "hello", 3.14)
    t: tuple = x

    EXPECT_EQ(len(t), 3)
    EXPECT_EQ(t[0], 1)
    EXPECT_EQ(t[1], "hello")
    EXPECT_EQ(t[2], 3.14)


# # ============================================================================
# # 元组方法测试
# # ============================================================================


@test("TupleMethods", "Count")
def test_tuple_count():
    """测试元组 count 方法"""

    t1: tuple = (1, 2, 3, 2, 1, 2)
    EXPECT_EQ(t1.count(1), 2)
    EXPECT_EQ(t1.count(2), 3)
    EXPECT_EQ(t1.count(3), 1)
    EXPECT_EQ(t1.count(4), 0)

    t2 = (1, 2, 3, 2, 1, 2)
    EXPECT_EQ(t2.count(1), 2)
    EXPECT_EQ(t2.count(2), 3)
    EXPECT_EQ(t2.count(3), 1)
    EXPECT_EQ(t2.count(4), 0)


@test("TupleMethods", "Index")
def test_tuple_index():
    """测试元组 index 方法"""

    t: tuple = (1, 2, 3, 2, 1)
    EXPECT_EQ(t.index(1), 0)
    EXPECT_EQ(t.index(2), 1)
    EXPECT_EQ(t.index(3), 2)


@test("TupleMethods", "IndexNotFound")
def test_tuple_index_not_found():
    """测试 index 方法找不到元素（应该抛出异常）"""

    t: tuple = (1, 2, 3)
    try:
        _ = t.index(4)  # 应该抛出异常
        EXPECT_TRUE(False)  # 不应该到达这里
    except Exception:
        EXPECT_TRUE(True)  # 应该抛出异常


# # ============================================================================
# # 异步函数中的元组测试
# # ============================================================================


@test("TupleAsync", "LiteralWithAwait")
def test_tuple_literal_with_await():
    """测试异步函数中的元组字面量构造（带 await）"""

    async def get_value(x: int) -> int:
        return x * 2

    async def process() -> tuple[int, int, int]:
        result: tuple[int, int, int] = (
            await get_value(1),
            await get_value(2),
            await get_value(3),
        )
        return result

    result = ensure_future(process()).get()
    EXPECT_EQ(len(result), 3)
    EXPECT_EQ(result[0], 2)
    EXPECT_EQ(result[1], 4)
    EXPECT_EQ(result[2], 6)


@test("TupleAsync", "LiteralWithMixedAwait")
def test_tuple_literal_with_mixed_await():
    """测试元组字面量中部分元素带 await"""

    async def get_int() -> int:
        return 10

    async def get_str() -> str:
        return "hello"

    async def process() -> tuple[int, str, int]:
        result: tuple[int, str, int] = (
            await get_int(),
            await get_str(),
            42,  # 同步值
        )
        return result

    result = ensure_future(process()).get()
    EXPECT_EQ(len(result), 3)
    EXPECT_EQ(result[0], 10)
    EXPECT_EQ(result[1], "hello")
    EXPECT_EQ(result[2], 42)


@test("TupleAsync", "ReturnTuple")
def test_async_return_tuple():
    """测试异步函数返回元组"""

    async def get_tuple() -> tuple[int, str]:
        return (1, "hello")

    result = ensure_future(get_tuple()).get()
    EXPECT_EQ(len(result), 2)
    EXPECT_EQ(result[0], 1)
    EXPECT_EQ(result[1], "hello")


@test("TupleAsync", "TupleToAny")
def test_async_tuple_to_any():
    """测试异步函数中元组赋值给 Any"""

    async def get_tuple() -> tuple[int, str]:
        return (1, "hello")

    async def process() -> Any:
        t: tuple[int, str] = await get_tuple()
        x: Any = t  # 赋值给 Any
        return x

    result = ensure_future(process()).get()
    EXPECT_EQ(len(result), 2)
    EXPECT_EQ(result[0], 1)
    EXPECT_EQ(result[1], "hello")


# # ============================================================================
# # 嵌套和复杂场景测试
# # ============================================================================


@test("TupleComplex", "NestedTuple")
def test_nested_tuple():
    """测试嵌套元组"""

    t: tuple[tuple[int, int], tuple[str, str]] = ((1, 2), ("a", "b"))
    EXPECT_EQ(len(t), 2)
    EXPECT_EQ(len(t[0]), 2)
    EXPECT_EQ(len(t[1]), 2)
    EXPECT_EQ(t[0][0], 1)
    EXPECT_EQ(t[0][1], 2)
    EXPECT_EQ(t[1][0], "a")
    EXPECT_EQ(t[1][1], "b")


@test("TupleComplex", "TupleInList")
def test_tuple_in_list():
    """测试列表中的元组"""

    lst: list[tuple[int, str]] = [(1, "a"), (2, "b"), (3, "c")]
    EXPECT_EQ(len(lst), 3)
    EXPECT_EQ(lst[0][0], 1)
    EXPECT_EQ(lst[0][1], "a")
    EXPECT_EQ(lst[1][0], 2)
    EXPECT_EQ(lst[1][1], "b")


@test("TupleComplex", "TupleInDict")
def test_tuple_in_dict():
    """测试字典中的元组（作为值）"""

    d: dict[str, tuple[int, int]] = {"a": (1, 2), "b": (3, 4)}
    EXPECT_EQ(len(d), 2)
    EXPECT_EQ(d["a"][0], 1)
    EXPECT_EQ(d["a"][1], 2)
    EXPECT_EQ(d["b"][0], 3)
    EXPECT_EQ(d["b"][1], 4)


# # ============================================================================
# # 元组解包测试
# # ============================================================================


@test("TupleUnpack", "BasicUnpack")
def test_tuple_unpack():
    """测试元组解包"""

    t: tuple[int, str, int] = (1, "hello", 3)
    a, b, c = t
    EXPECT_EQ(a, 1)
    EXPECT_EQ(b, "hello")
    EXPECT_EQ(c, 3)


@test("TupleUnpack", "UnpackWithAwait")
def test_tuple_unpack_with_await():
    """测试异步函数中元组解包"""

    async def get_tuple() -> tuple[int, str]:
        return (1, "hello")

    async def process() -> int:
        a, b = await get_tuple()
        return a

    result = ensure_future(process()).get()
    EXPECT_EQ(result, 1)
